package com.xhlj.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.util.DateUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xhlj.entity.Rule;
import com.xhlj.entity.UserInfo;
import com.xhlj.mapper.RuleMapper;
import com.xhlj.mapper.UserInfoMapper;
import com.xhlj.service.RuleService;
import com.xhlj.service.UserInfoService;
import com.xhlj.utils.PayLoad;
import com.xhlj.utils.RedisKey;
import com.xhlj.utils.Result;
import jakarta.annotation.Resource;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisHash;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;


import java.util.*;
import java.util.concurrent.TimeUnit;


/**
 * @author dell
 * @description 针对表【rule】的数据库操作Service实现
 * @createDate 2024-03-01 10:38:12
 */
@Service
public class RuleServiceImpl extends ServiceImpl<RuleMapper, Rule>
        implements RuleService {
    @Resource
    private RuleMapper ruleMapper;
    @Resource
    private UserInfoMapper userInfoMapper;
    @Resource
    private UserInfoService userInfoService;
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public Result getList() {
        return Result.ok(ruleMapper.selectList(null));
    }

    /*
     * 判断是否只能一次
     * */
    public int checkIsOnly(Integer ruleId) {
        LambdaQueryWrapper<Rule> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Rule::getRuleId, ruleId);
        Rule rule = this.getOne(wrapper);

        return rule.getRuleIsDisposable();
    }

    /*
     * 判断是否只能一次
     * @param ruleId 规则ID
     * @return 0 表示不是只能一次,1 表示只能完成一次且没有完成,2表示是完成一次,且已经完成
     * */
    public boolean checkIsDaily(Integer ruleId) {
        LambdaQueryWrapper<Rule> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Rule::getRuleId, ruleId);
        Rule rule = this.getOne(wrapper);

        return rule.getRuleIsDaily() == 1;
    }

    /*
     * 初始化每日任务的状态:0表示没有完成,1表示已经完成
     * @param payLoad token的数据
     *
     * */
    public void initDailyTaskStatus(PayLoad payLoad) {
        String key = RedisKey.Task_prefix + JSON.toJSONString(payLoad).replaceAll(":", "@");

        LambdaQueryWrapper<Rule> wrapper = new LambdaQueryWrapper<>();
        //直接算一下距离下一天5点的毫秒
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(new Date());

        //转换得到今天的日期:2024-03-09
        String today = DateUtils.format(calendar.getTime(), "yyyy-MM-dd");
        //转换得倒明天的日期:2024-03-10 05:59
        calendar.add(Calendar.DATE, +1);
        calendar.set(Calendar.HOUR_OF_DAY, 4);
//        String tomorrowString = DateUtils.format(calendar.getTime(), "yyyy-MM-dd HH:mm");
        Date tomorrow = calendar.getTime();
        //拿到当天的时间戳
        long now = System.currentTimeMillis();
        //key的时间一直持续到次日5点
        wrapper.eq(Rule::getRuleIsDaily, 1);
        List<Rule> ruleList = ruleMapper.selectList(wrapper);
        for (Rule rule : ruleList) {
            if (Boolean.FALSE.equals(stringRedisTemplate.hasKey(key + rule.getRuleId()))) {
                ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
                ops.set(key + rule.getRuleId(), "0", tomorrow.getTime() - now, TimeUnit.MILLISECONDS);
            }

        }

    }

    /*
     * 更新某个每日任务的状态 ,应该只需要设置value就行了
     * */
    public boolean updateTaskStatus(PayLoad payLoad, Integer ruleId) {

        //直接算一下距离下一天5点的毫秒
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(new Date());

        //转换得到今天的日期:2024-03-09
        String today = DateUtils.format(calendar.getTime(), "yyyy-MM-dd");
        //转换得倒明天的日期:2024-03-10 05:59
        calendar.add(Calendar.DATE, +1);
        calendar.set(Calendar.HOUR_OF_DAY, 4);
//        String tomorrowString = DateUtils.format(calendar.getTime(), "yyyy-MM-dd HH:mm");
        Date tomorrow = calendar.getTime();
        //拿到当天的时间戳
        long now = System.currentTimeMillis();
        //key的时间一直持续到次日5点
        LambdaQueryWrapper<Rule> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Rule::getRuleIsDaily, 1)
                .eq(Rule::getRuleId, ruleId);
        Rule rule = ruleMapper.selectOne(wrapper);
        String key = RedisKey.Task_prefix + JSON.toJSONString(payLoad).replaceAll(":", "@") + ruleId;

        ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
        if (Boolean.FALSE.equals(stringRedisTemplate.hasKey(key + rule.getRuleId()))
                && "0".equals(ops.get(key ))) {
            /*stringRedisTemplate.execute(new RedisCallback<Object>() {
                @Override
                public Object doInRedis(RedisConnection connection) throws DataAccessException {
                    connection.set(( key).getBytes(), "1".getBytes());
                    return null;
                }

                垃圾
            });*/

            ops.set(key, "1", tomorrow.getTime() - now, TimeUnit.MILLISECONDS);
            return true;
        }
        return false;

    }

    @Override
    public Result completeDaily(Integer ruleId) {
        String username = SecurityContextHolder.getContext().getAuthentication().getName();
        PayLoad payLoad = userInfoService.createPayLoad(username);
        if (checkIsDaily(ruleId)) {
            updatePoint(ruleId);
            boolean res = updateTaskStatus(payLoad, ruleId);
            if (res)
                return Result.build(null, 200, "完成任务成功");
            else
                return Result.build(null, 400, "今天已经完成了");

//            public static String Task_prefix = basePrefix + "task:";
        }
        return Result.build(null, 400, "不是每日任务");
    }

    @Override
    @Transactional
    public Result completeTask(Integer ruleId) {
        if (checkIsOnly(ruleId) == 1) {
            updatePoint(ruleId);
            /*更新is_dispose...*/
            LambdaUpdateWrapper<Rule> wrapper = new LambdaUpdateWrapper<>();
            wrapper.eq(Rule::getRuleId, ruleId)
                    .set(Rule::getRuleIsDisposable, 2);
            ruleMapper.update(wrapper);
            return Result.build(null, 200, "任务完成");
        } else if (checkIsOnly(ruleId) == 2) {
            return Result.build(null, 400, "任务已经完成,且只能完成一次");
        } else {
            updatePoint(ruleId);
            return Result.build(null, 200, "任务完成");

        }
    }


    @Transactional(propagation = Propagation.SUPPORTS)
    public boolean updatePoint(Integer ruleId) {
        SecurityContext context = SecurityContextHolder.getContext();
        Authentication authentication = context.getAuthentication();
        String username = authentication.getName();
        int point = ruleMapper.selectById(ruleId).getRulePoint();

        LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserInfo::getUserPhone, username);
        UserInfo userInfo = userInfoService.getOne(wrapper);
        int old = userInfo.getUserPoints();

        LambdaUpdateWrapper<UserInfo> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(UserInfo::getUserPhone, username)
                .set(UserInfo::getUserPoints, old + point);
        int update = userInfoMapper.update(null, updateWrapper);
        return update > 0;
    }
}




